import getLastEvent from "./getLastEvent.js";
import getSelector from "./getSelector.js";

function getLines(stack) {
    return stack
        .split('\n')
        .slice(1)
        .map((item) => item.replace(/^\s+at\s+/g, ''))
        .join('^')
}

function getExtraData() {
    return {
        title: document.title,
        url: location.href,
        timestamp: Date.now(),
        userAgent: navigator.userAgent
    }
}

function injectJsError(callback) {
    // 监听全局未捕获的错误
    window.addEventListener(
        'error',
        (event) => {
            let lastEvent = getLastEvent() // 获取到最后一个交互事件
            // 脚本加载错误
            if (event.target && (event.target.src || event.target.href)) {
                callback({
                    kind: 'stability', // 监控指标的大类，稳定性
                    type: 'error', // 小类型，这是一个错误
                    errorType: 'resourceError', // js执行错误
                    filename: event.target.src || event.target.href, // 哪个文件报错了
                    tagName: event.target.tagName,
                    selector: getSelector(event.target), // 代表最后一个操作的元素
                    ...getExtraData(),
                })
            } else {
                callback({
                    kind: 'stability', // 监控指标的大类，稳定性
                    type: 'error', // 小类型，这是一个错误
                    errorType: 'jsError', // js执行错误
                    message: event.message, // 报错信息
                    filename: event.filename, // 哪个文件报错了
                    position: {
                        col: event.colno,
                        row: event.lineno
                    }, // 报错的行列位置
                    stack: getLines(event.error.stack),
                    selector: lastEvent ? getSelector(lastEvent.path) : '', // 代表最后一个操作的元素
                    ...getExtraData(),
                })
            }
        },
        true
    )

    window.addEventListener(
        'unhandledrejection',
        (event) => {
            let lastEvent = getLastEvent() // 获取到最后一个交互事件
            let message
            let filename
            let line = 0
            let column = 0
            let stack = ''
            let reason = event.reason
            if (typeof reason === 'string' || typeof reason === 'number') {
                message = reason
            } else if (typeof reason === 'object') {
                message = reason.message
                if (reason.stack) {
                    let matchResult = reason.stack.match(/at\s+(.+):(\d+):(\d+)/)
                    filename = matchResult[1]
                    line = matchResult[2]
                    column = matchResult[3]
                }
                stack = getLines(reason.stack)
            }
            callback({
                kind: 'stability', // 监控指标的大类，稳定性
                type: 'error', // 小类型，这是一个错误
                errorType: 'promiseError', // js执行错误
                message, // 报错信息
                filename, // 哪个文件报错了
                position: {
                    col: column,
                    row: line
                }, // 报错的行列位置
                stack,
                selector: lastEvent ? getSelector(lastEvent.path) : '', // 代表最后一个操作的元素
                ...getExtraData(),
            })
        },
        true
    )
}

export default injectJsError


